package me.yricky.cov_spectrum.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import me.yricky.cov_spectrum.app
import me.yricky.cov_spectrum.model.ApiModel
import me.yricky.cov_spectrum.model.beans.CommonApiBean
import me.yricky.cov_spectrum.model.beans.PangoLineageAliasItem
import me.yricky.cov_spectrum.model.beans.PangoLineageItem

class PangoLineageViewModel:ViewModel() {
    //api直接返回的数据，缓存在viewModel
    private val _itemList: MutableStateFlow<List<PangoLineageItem>> = MutableStateFlow(emptyList())
    private val _aliasMap:MutableStateFlow<Map<String,PangoLineageAliasItem>> = MutableStateFlow(emptyMap())

    private val _sortBy:MutableStateFlow<SortBy> = MutableStateFlow(SortBy.Default(false))
    private val _stat:MutableStateFlow<LoadingStatus> = MutableStateFlow(LoadingStatus.Loading)
    private val _viewList:MutableStateFlow<List<PangoLineageItem>> = MutableStateFlow(emptyList())

    private val aliasNameMap = mutableMapOf<String,String>()

    val viewList = _viewList.asStateFlow()
    val loadingStatus = _stat.asStateFlow()
    val sortBy = _sortBy.asStateFlow()

    fun getFullName(pangoLineageName:String):String{
        aliasNameMap[pangoLineageName]?.let {
            return it
        }
        val prefix = pangoLineageName.indexOfFirst { it == '.' }.let {
            if( it < 0 ){ pangoLineageName.length }else{ it }
        }
        val alias = prefix.let{_aliasMap.value[pangoLineageName.substring(0,it)]}
        return if(alias != null){
            "${alias.fullName}${pangoLineageName.substring(prefix)}".also {
                aliasNameMap[pangoLineageName] = it
            }
        }else{
            aliasNameMap[pangoLineageName] = pangoLineageName
            pangoLineageName
        }
    }

    fun setSortBy(sortBy: SortBy){
        _sortBy.value = sortBy
        viewModelScope.launch(Dispatchers.Default) {
            _stat.value = LoadingStatus.Loading
            _viewList.value = _sortBy.value.sort(_itemList.value)
            _stat.value = LoadingStatus.Success
        }
    }

    fun reloadList(){
        viewModelScope.launch {
            _stat.value = LoadingStatus.Loading
            val req1 = async(Dispatchers.IO){
                try{
                    ApiModel.getPangoLineage(app.userCfg.get().accessKey)
                        .getOrThrow()
                }catch (e:Throwable){
                    _stat.value = LoadingStatus.Error(e)
                    CommonApiBean(
                        errors = listOf(CommonApiBean.Error(e.localizedMessage ?: "")),
                        null,
                        data = emptyList()
                    )
                }
            }
            val req2 = async(Dispatchers.IO) {
                ApiModel.getPangoLineageAlias().getOrNull()?.associateBy { it.alias }
            }
            _itemList.value = req1.await().data ?: emptyList()
            if(_itemList.value.isNotEmpty()){
                _viewList.value = sortBy.value.sort(_itemList.value)
                _stat.value = LoadingStatus.Success
            }else if(req1.await().errors.isNotEmpty()){
                _stat.value = LoadingStatus.Error(java.lang.RuntimeException(
                    req1.await().errors.map { it.message }.reduce{ str1,str2 -> "$str1\n$str2" }
                ))
            }
            _aliasMap.value = req2.await() ?: emptyMap()
            aliasNameMap.clear()
        }
    }

    init {
        reloadList()
    }

    sealed class SortBy(val reversed:Boolean){
        abstract fun sort(list:List<PangoLineageItem>):List<PangoLineageItem>
        abstract fun reverse():SortBy
        class Default(reversed: Boolean) : SortBy(reversed) {
            override fun sort(list: List<PangoLineageItem>): List<PangoLineageItem> {
                return if(reversed) list.asReversed() else list
            }

            override fun reverse(): SortBy =Default(!reversed)
        }

        class Name(reversed: Boolean) : SortBy(reversed) {
            override fun sort(list: List<PangoLineageItem>): List<PangoLineageItem> {
                return if(reversed) list.sortedBy { it.pangoLineage }.asReversed() else list.sortedBy { it.pangoLineage }
            }
            override fun reverse(): SortBy =Name(!reversed)

        }

        class Count(reversed: Boolean):SortBy(reversed) {
            override fun sort(list: List<PangoLineageItem>): List<PangoLineageItem> {
                return if(reversed) list.sortedBy { -it.count } else list.sortedBy { it.count }
            }
            override fun reverse(): SortBy =Count(!reversed)
        }
    }
}